<template>
  <div class="ai-wrap">
    <div
      v-if="showProgress"
      :class="progressType === 0 ? 'progress-alert big' : 'progress-alert small'"
    >
      <div v-if="progressType === 0" class="progress-title">
        <el-icon><CircleCheckFilled /></el-icon>
        提交成功
      </div>
      <div v-if="progressType === 0" class="progress-desc">{{ progressDesc }}</div>
      <el-progress :percentage="progressVal" />
      <el-icon v-if="progressType === 0" class="progress-close" @click="progressType = 1"
        ><Close
      /></el-icon>
    </div>
    <el-tabs v-model="activeTab" class="all-tabs">
      <el-tab-pane label="AI生图" name="0"></el-tab-pane>
      <el-tab-pane label="AI图库" name="1"></el-tab-pane>
    </el-tabs>
    <div v-if="activeTab === '0'" class="first-content">
      <h3>风格</h3>
      <div class="select-type-container">
        <div
          v-for="item in styleList"
          :key="item.id"
          :class="
            activeStyle === item.id ? 'select-type-content-item active' : 'select-type-content-item'
          "
          @click="() => onSelectStyle(item.id)"
        >
          <img :src="item.cover" />
          <span>{{ item.label }}</span>
        </div>
        <!-- <div class="open-all">展开所有 <img :src="downIcon" /></div> -->
      </div>
      <h3>画面描述</h3>
      <div class="top-input">
        <el-input
          v-model="inputVal"
          class="input-content"
          size="large"
          type="textarea"
          maxlength="600"
          :autosize="{ minRows: 4, maxRows: 8 }"
          placeholder="请输入图片描述"
        />
        <div class="input-bottom">
          <div class="bottom-left">
            <!-- <span><img :src="penIcon" alt="" />帮我写</span> -->
            <span @click="showSelectWords = true"><img :src="penIcon" alt="" />咒语</span>
          </div>
          <div class="bottom-right">
            <span>{{ inputVal.length }}/600</span>
            <span @click="inputVal = ''">清空</span>
          </div>
        </div>
      </div>
      <div class="selected-words">
        <el-tag
          v-for="tag in selectWords"
          :key="tag.chinese"
          size="default"
          class="mx-1"
          closable
          :type="tag.type"
          @close="() => onDeleteWord(tag)"
        >
          {{ tag.chinese }}
        </el-tag>
      </div>
      <div class="draw-content">
        <h3>图片参考</h3>
        <div class="draw-list">
          <div
            v-for="(item, index) in consistentList"
            :key="index"
            :class="['draw-item', activeConsistent === index ? 'active' : '']"
            @click="activeConsistent = index"
          >
            {{ item.label }}
          </div>
        </div>
        <upload-image :imageUrl="aiImage" @change="onAIImageChange" />
      </div>
      <div class="draw-content">
        <h3>渲染</h3>
        <div class="draw-list">
          <div
            v-for="(item, index) in renderList"
            :key="index"
            :class="['draw-item', activeRender === index ? 'active' : '']"
            @click="activeRender = index"
          >
            {{ item.label }}
          </div>
        </div>
      </div>
      <div v-if="activeRender === 1" class="draw-content render-type-list">
        <div class="draw-list">
          <div
            v-for="(item, index) in renderTypeList"
            :key="index"
            :class="['draw-item', activeRenderType === index ? 'active' : '']"
            @click="activeRenderType = index"
          >
            {{ item.label }}
          </div>
        </div>
        <el-slider
          v-if="activeRenderType === 5"
          v-model="customStyleNumber"
          :max="1000"
          :min="0"
          :step="100"
          show-stops
          marks
        />
      </div>
      <div class="size-content">
        <h3>比例</h3>
        <div class="size-list">
          <div
            v-for="(item, index) in sizeList"
            :key="index"
            :class="['size-item', activeSize === index ? 'active' : '']"
            @click="activeSize = index"
          >
            <div class="size-inner">
              <size-icons :type="item.label" :color="activeSize === index ? '#3366ff' : ''" />
              <span>{{ item.label }}</span>
            </div>
          </div>
        </div>
      </div>
      <div class="draw-content">
        <h3>画质</h3>
        <div class="draw-list">
          <div
            v-for="(item, index) in drawList"
            :key="index"
            :class="['draw-item', activeDraw === index ? 'active' : '']"
            @click="activeDraw = index"
          >
            {{ item.label }}
          </div>
        </div>
      </div>
      <div class="bottom-btn">
        <el-button
          type="primary"
          size="default"
          :disabled="canUseCount <= 0"
          :loading="submitLoading"
          @click="() => createTask()"
          >确定生成({{ canUseCount === 0 ? '可用次数不足' : '剩余次数-1' }})</el-button
        >
        <p>当天剩余可生成：{{ canUseCount }}次</p>
      </div>
    </div>
    <div v-else class="ai-history">
      <infinte-task @use="onUseTask" @retry="onRetryCreate" />
    </div>
    <el-drawer v-model="showSelectWords" append-to-body size="700px" title="请选择咒语">
      <tag-list @change="onWordsChange" />
      <template #footer>
        <div class="dialog-bottom-btns">
          <el-button size="default" :disabled="confirmLoading">取消</el-button>
          <el-button
            size="default"
            type="primary"
            :loading="confirmLoading"
            @click="confirmSelectWords"
            >确定</el-button
          >
        </div>
      </template>
    </el-drawer>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { createAITask, getAITaskDetail } from '@/api/ai'
import qs from 'query-string'
import {
  sizeList,
  drawList,
  renderList,
  consistentList,
  styleList,
  renderTypeList,
  getStyleIdByPrompt,
} from '@/constants/ai'
import { ElMessage } from 'element-plus'
import { getQuality, getRatio, getCurrentRatio, getRender, getRenderType } from '@/utils/prompt'
import TagList from './tagList.vue'
import SizeIcons from './sizeIcons.vue'
import penIcon from '@/assets/images/pen.svg'
import downIcon from '@/assets/images/down.svg'
import eventBus from '@/utils/eventBus'

// 获取5到10之间的数
const getRandom = () => {
  return Math.floor(Math.random() * 5 + 5)
}

export default defineComponent({
  progressTimer: null,
  components: {
    TagList,
    SizeIcons,
  },
  props: ['active'],
  data(): any {
    return {
      penIcon,
      downIcon,
      inputVal: '',
      activeTab: '0',
      activeSize: 0,
      sizeList,
      drawList,
      renderList,
      consistentList,
      styleList,
      renderTypeList,
      activeDraw: 1,
      activeRender: 0,
      activeConsistent: 0,
      activeType: 0,
      customStyleNumber: 500,
      activeImg: 0,
      activeStyle: -1,
      activeRenderType: 0,
      submitLoading: false,
      progress: 0,
      showProgress: false,
      progressType: 0,
      taskUnDone: false,
      showSelectWords: false,
      selectWords: [],
      hasCreatedImage: false,
      createImageProgress: '0%',
      aiImage: '',
      confirmLoading: false,
      canUseCount: 30,
      userInfo: {
        id: 0,
        name: '',
        email: '',
      },
    }
  },
  computed: {
    progressVal() {
      if (this.hasCreatedImage) {
        return this.createImageProgress.split('%')[0] / 2 + 50
      }
      return this.progress
    },
    progressDesc() {
      if (this.hasCreatedImage) {
        return '正在生成图片，请耐心等待'
      }
      return '正在生成图片，请耐心等待'
    },
    // 已选择咒语的英文
    selectEnglishWords() {
      return this.selectWords.map((item: any) => item.english).join(',')
    },
    selectChineseWords() {
      return this.selectWords.map((item: any) => item.chinese).join(',')
    },
    // 已选择风格的英文
    selectedStyleEnglish() {
      const activeStyleObj = styleList.find((item) => item.id === this.activeStyle)
      if (activeStyleObj) {
        return activeStyleObj.prompt
      }
      return ''
    },
  },
  mounted() {
    eventBus.on('click-diantu', (imgUrl) => {
      console.log('imgUrl1: ', imgUrl)
      this.aiImage = imgUrl
    })
  },
  methods: {
    ...mapActions(['selectWidget', 'updatePageData', 'addWidget', 'getRemainCount']),
    ...mapMutations(['setSelectAIImageUrl']),
    // 创建任务
    async createTask() {
      // 当前任务还没完成
      if (this.taskUnDone) {
        ElMessage('请等待当前任务完成')
        return
      }
      if (!this.inputVal) {
        ElMessage.warning('请输入图片描述')
        return
      }
      this.submitLoading = true
      // 描述语英文
      const englishText = await this.translate()
      if (!englishText) {
        this.submitLoading = false
        return
      }
      // 结尾参数 ： 拿到后缀
      const lastParams = this.getLastParams()
      // 咒语关键字
      let finallyPrompt = `${englishText},${this.selectEnglishWords} ${this.selectedStyleEnglish}`
      // 参考图
      if (this.aiImage) {
        if (this.aiImage.indexOf('imageView2') > -1) {
          const urlObj = qs.parseUrl(this.aiImage)
          const url = urlObj.url
          if (this.activeConsistent === 2) {
            finallyPrompt = `${finallyPrompt} --sref ${url}?imageView2/2/w/100/format/png/ --sw 300 --v 6.0`
          } else if (this.activeConsistent === 1) {
            finallyPrompt = `${finallyPrompt} --cref ${url}?imageView2/2/w/100/format/png/ --cw 100 --v 6.0`
          } else finallyPrompt = url + '?imageView2/2/w/100/format/png/' + ' ' + finallyPrompt
        } else {
          if (this.activeConsistent === 2) {
            finallyPrompt = `${finallyPrompt} --sref ${this.aiImage}?imageView2/2/w/100/format/png/ --sw 300 --v 6.0`
          } else if (this.activeConsistent === 1) {
            finallyPrompt = `${finallyPrompt} --cref ${this.aiImage}?imageView2/2/w/100/format/png/ --cw 100 --v 6.0`
          } else
            finallyPrompt = this.aiImage + '?imageView2/2/w/100/format/png/' + ' ' + finallyPrompt
        }
      }
      finallyPrompt = `${finallyPrompt} ${lastParams}`
      console.log('finallyPrompt: ', finallyPrompt)
      this.createTaskByPrompt(finallyPrompt, this.inputVal)
    },
    async createTaskByPrompt(prompt: string, chinesePrompt?: string) {
      const userInfo = this.userInfo
      try {
        const data = await createAITask({
          emp_id: userInfo.id,
          emp_name: userInfo.name,
          email: userInfo.email,
          prompt: prompt,
          chinese_prompt: chinesePrompt,
        })
        await this.getRemainCount()
        this.taskUnDone = true
        this.submitLoading = false
        if (data.id) {
          this.showProgress = true
          if (this.progressTimer) {
            clearInterval(this.progressTimer)
            this.progressTimer = null
          }
          this.progressTimer = setInterval(async () => {
            let newProgress = (this.progress += getRandom())
            newProgress > 49 ? (this.progress = 49) : (this.progress = newProgress)
            const taskData = await getAITaskDetail(data.id)
            if (taskData.progress) {
              this.hasCreatedImage = true
              this.createImageProgress = taskData.progress
            }
            // 任务完成
            if (taskData.response_state === 1 && taskData.oss_url) {
              clearInterval(this.progressTimer)
              this.progressTimer = null
              this.progress = 0
              this.hasCreatedImage = false
              this.createImageProgress = '0%'
              ElMessage.success({
                message: '生成成功',
                duration: 2000,
              })
              this.showProgress = false
              this.taskUnDone = false
              this.progressType = 0
              // this.setSelectAIImageUrl({
              //   imageUrl: taskData.oss_url,
              //   taskId: taskData.id,
              //   prompt: taskData.prompt,
              //   chinesePrompt: taskData.chinese_prompt,
              //   styleId: this.activeStyle,
              // })
            }
            // 任务生成失败
            if (taskData.response_state === 2) {
              clearInterval(this.progressTimer)
              this.progressTimer = null
              this.progress = 0
              this.hasCreatedImage = false
              this.createImageProgress = '0%'
              ElMessage.error({
                message: '生成失败，请点击重试',
                duration: 2000,
              })
              this.showProgress = false
              this.taskUnDone = false
              this.progressType = 0
            }
          }, 3000)
        }
        console.log('data', data)
      } catch (err: any) {
        ElMessage(err?.message)
        this.submitLoading = false
        this.progressType = 0
      }
    },
    onRetryCreate(propmt: string, chinese_prompt?: string) {
      this.createTaskByPrompt(propmt, chinese_prompt)
      this.activeTab = '0'
    },
    onSelectStyle(id: number) {
      console.log('id: ', id)
      if (this.activeStyle === id) {
        this.activeStyle = -1
      } else {
        this.activeStyle = id
      }
    },
    onUseTask(task: any) {
      this.setSelectAIImageUrl({
        imageUrl: task.oss_url,
        taskId: task.id,
        prompt: task.prompt,
        chinesePrompt: task.chinese_prompt,
        styleId: getStyleIdByPrompt(task.prompt),
      })
    },
    onAIImageChange(val: string) {
      console.log('val: ', val)
      if (val) {
        this.aiImage = val[0]
      } else {
        this.aiImage = ''
      }
    },
    getLastParams() {
      const size = this.sizeList[this.activeSize].label
      let sizeStr = ''
      if (size === '按画布尺寸') {
        sizeStr = getCurrentRatio({ width: 1000, height: 800 }) //根据画布尺寸获取宽高比例
      } else {
        sizeStr = getRatio(size)
      }
      const quality = this.drawList[this.activeDraw].id
      const qualityStr = getQuality(quality) // 获取图片质量
      const renderStr = getRender(this.activeRender)
      let renderTypeStr = ''
      if (this.activeRender === 1) {
        // 自定义数值
        if (this.activeRenderType === 5) {
          renderTypeStr = ' --style raw --stylize ' + this.customStyleNumber
        } else {
          renderTypeStr = getRenderType(this.activeRenderType)
        }
      }
      return sizeStr + qualityStr + renderStr + renderTypeStr
    },
    onWordsChange(selectWords: string[]) {
      this.selectWords = selectWords
    },
    onDeleteWord(tag: any) {
      const findIndex = this.selectWords.findIndex((item: any) => item.chinese === tag.chinese)
      if (findIndex > -1) {
        this.selectWords.splice(findIndex, 1)
      }
    },
    confirmSelectWords() {
      this.showSelectWords = false
    },
    async translate() {
      try {
        const res = await translate(this.inputVal)
        console.log('res: ', res)
        if (res) {
          return res.text
        } else {
          ElMessage.error('翻译失败：')
          return false
        }
      } catch (err: any) {
        console.error('err: ', err)
        ElMessage.error('翻译失败：' + err?.message)
        return false
      }
    },
  },
})
</script>

<style lang="less" scoped>
.ai-wrap {
  width: 300px;
  height: 100%;
  padding: 10px;
  position: relative;
  border-right: 1px solid #ccc;
  .top-input {
    margin-bottom: 10px;
  }
  .select-type-list {
    display: flex;
    width: 272px;
    padding: 4px;
    align-items: center;
    gap: 4px;
    border-radius: 8px;
    background: #f4f4f4;
    .type-item {
      display: flex;
      width: 130px;
      padding: 4px 0;
      justify-content: center;
      align-items: center;
      gap: 10px;
      flex-shrink: 0;
      border-radius: 4px;
      color: rgba(0, 0, 0, 0.65);
      font-size: 14px;
      font-weight: 600;
      line-height: 22px;
      cursor: pointer;
      &.active {
        background: #fff;
        color: #000;
      }
    }
  }
  .first-content {
    overflow-y: auto;
    max-height: calc(100vh - 210px);
    h3 {
      color: rgba(0, 0, 0, 0.85);
      font-size: 14px;
      font-weight: 600;
      line-height: 20px;
      margin-bottom: 8px;
    }
    .selected-words {
      margin-bottom: 14px;
      .el-tag {
        margin-right: 4px;
        margin-bottom: 4px;
        color: #333;
      }
    }
  }
  .select-type-container {
    margin-top: 10px;
    padding-left: 2px;
    display: flex;
    flex-wrap: wrap;
    gap: 13px;
    position: relative;
    padding-bottom: 20px;
    .select-type-content-item {
      width: 82px;
      height: 82px;
      flex: 0 0 82px;
      border-radius: 4px;
      padding: 1px;
      position: relative;
      // overflow: hidden;
      cursor: pointer;
      &.active {
        &::after {
          content: '';
          display: block;
          width: 80px;
          height: 80px;
          border: 2px solid #36f;
          position: absolute;
          left: -2px;
          top: -2px;
          border-radius: 4px;
        }
      }
      img {
        width: 78px;
        height: 78px;
        position: absolute;
        border-radius: 4px;
      }
      span {
        display: flex;
        // height: 24px;
        padding: 4px 0;
        width: 78px;
        justify-content: center;
        align-items: center;
        background: rgba(0, 0, 0, 0.4);
        color: #fff;
        position: absolute;
        z-index: 2;
        bottom: 3px;
        font-size: 12px;
        text-align: center;
        backdrop-filter: blur(2px);
        border-bottom-left-radius: 4px;
        border-bottom-right-radius: 4px;
      }
    }
    .open-all {
      color: rgba(0, 0, 0, 0.45);
      font-size: 12px;
      font-weight: 400;
      line-height: 16px;
      cursor: pointer;
      position: absolute;
      bottom: -10px;
      left: 0;
      right: 0;
      margin: 0 auto;
      display: flex;
      justify-content: center;
      align-content: center;
      img {
        width: 16px;
        height: 16px;
        margin-bottom: 0;
      }
    }
  }
  .ai-history {
    overflow-y: auto;
    height: calc(100vh - 130px);
    .task-list-wrapper {
      // height: 100%;
    }
  }
  .size-content,
  .draw-content {
    padding-top: 10px;
    h3 {
      font-size: 14px;
    }
    .size-list,
    .draw-list {
      margin-top: 10px;
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      .size-item,
      .draw-item {
        padding: 8px 24px;
        width: 60px;
        // height: 40px;
        // line-height: 40px;
        border-radius: 4px;
        border: 1px solid #d9d9d9;
        text-align: center;
        background: #fff;
        margin-right: 10px;
        cursor: pointer;
        font-size: 12px;
        margin-bottom: 10px;
        &.active {
          color: var(--el-color-primary);
          border-color: var(--el-color-primary);
          font-weight: 600;
        }
        // &:hover {
        //   background-color: #b1baf1;
        // }
      }
      .draw-item {
        width: 82px;
        padding: 8px 0;
        font-weight: 300;
        &.active {
          border-width: 2px;
        }
      }
    }
    &.render-type-list {
      padding: 10px;
      padding-top: 0;
      .draw-item {
        width: 70px;
        height: 30px;
      }
    }
    .size-list {
      display: block;
      flex-wrap: wrap;
      .size-item {
        display: inline-block;
        width: auto;
        padding: 8px 12px;
        margin-right: 4px;
        .size-inner {
          // display: flex;
          // align-items: center;
          // justify-content: center;
          .size-icon {
            width: 20px;
            vertical-align: baseline;
          }
          span {
            margin-left: 4px;
          }
        }
      }
    }
    .draw-list {
      grid-template-columns: repeat(3, 1fr);
    }
  }
  .bottom-btn {
    position: absolute;
    bottom: 10px;
    // display: flex;
    // justify-content: center;
    width: 100%;
    left: 0;
    height: 80px;
    padding: 10px 20px;
    border-top: 1px solid #f0f0f0;
    .el-button {
      width: 100%;
    }
    p {
      margin-top: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: 300;
    }
  }
}
.dialog-bottom-btns {
  width: 100%;
  // margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}
</style>
<style lang="less">
.ai-wrap {
  .progress-alert {
    position: fixed !important;
    padding: 20px 24px;
    top: 60px;
    width: 400px;
    z-index: 999;
    background: #ffffff !important;
    width: 400px;
    height: 130px;
    &.big {
      left: 80px;
      right: 0;
      margin: 0 auto;
    }
    &.small {
      padding: 8px;
      width: 360px;
      height: auto;
      left: 370px;
      .el-progress {
        margin-top: 0;
      }
    }
    .progress-title {
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--02-text-85262626, rgba(0, 0, 0, 0.85));
      font-size: 16px;
      font-weight: 400;
      line-height: 18px;
      .el-icon {
        font-size: 30px;
        color: #00b377;
        margin-right: 4px;
      }
    }
    .progress-desc {
      color: var(--02-text-65595959, rgba(0, 0, 0, 0.65));
      font-size: 14px;
      font-weight: 400;
      line-height: 18px;
      margin-top: 20px;
      text-align: center;
    }
    .el-progress {
      margin-top: 10px;
    }
    .progress-close {
      width: 16px;
      height: 16px;
      font-size: 16px;
      position: absolute;
      right: 16px;
      top: 16px;
      cursor: pointer;
    }
  }
}
.top-input {
  background-color: #f7f9fc;
  padding: 14px 10px;
  border-radius: 8px;
  .input-content {
    .el-textarea__inner {
      padding: 0;
      box-shadow: none;
      background-color: #f7f9fc;
      border-bottom: 1px solid #dce6ed;
      border-radius: 0;
    }
  }
  .input-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 10px;
    .bottom-left,
    .bottom-right {
      display: flex;
      align-items: center;
    }
    span {
      display: flex;
      align-content: center;
      margin-right: 14px;
      color: rgba(0, 0, 0, 0.85);
      font-weight: 300;
      font-size: 12px;
      cursor: pointer;
      img {
        width: 16px;
        height: 16px;
      }
    }
    .bottom-right {
      span {
        margin-right: 0;
        margin-left: 14px;
        cursor: pointer;
      }
    }
  }
}
</style>
